﻿using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using DelayedQueue.Models;

namespace DelayedQueue.TimingWheel
{
    /// <summary>
    /// 时间轮实现，用于高效管理延时任务
    /// </summary>
    public class TimingWheel : IDisposable
    {
        private readonly int _slotCount;          // 槽位数量
        private readonly int _tickDurationMs;     // 每个槽位的时间间隔（毫秒）
        private readonly ConcurrentDictionary<string, (int slotIndex, int rounds)> _taskPositions = new ConcurrentDictionary<string, (int, int)>(); // 任务位置: (槽位索引, 圈数)
        private readonly ConcurrentQueue<DelayedTask>[] _slots;  // 槽位数组
        private readonly Timer _timer;             // 定时器，推动时间轮前进
        private int _currentSlotIndex;             // 当前指针位置
        private bool _isRunning;
        private bool _isDisposed;
        private readonly Action<DelayedTask> _taskExecutor; // 任务执行器

        /// <summary>
        /// 初始化时间轮
        /// </summary>
        /// <param name="slotCount">槽位数量</param>
        /// <param name="tickDurationMs">每个槽位的时间间隔（毫秒）</param>
        /// <param name="taskExecutor">任务执行回调</param>
        public TimingWheel(int slotCount, int tickDurationMs, Action<DelayedTask> taskExecutor)
        {
            if (slotCount <= 0)
                throw new ArgumentException("槽位数量必须大于0", nameof(slotCount));

            if (tickDurationMs <= 0)
                throw new ArgumentException("时间间隔必须大于0", nameof(tickDurationMs));

            _slotCount = slotCount;
            _tickDurationMs = tickDurationMs;
            _taskExecutor = taskExecutor ?? throw new ArgumentNullException(nameof(taskExecutor));

            // 初始化槽位
            _slots = new ConcurrentQueue<DelayedTask>[_slotCount];
            for (int i = 0; i < _slotCount; i++)
            {
                _slots[i] = new ConcurrentQueue<DelayedTask>();
            }

            // 初始化定时器
            _timer = new Timer(OnTimerElapsed, null, Timeout.Infinite, Timeout.Infinite);
        }

        /// <summary>
        /// 启动时间轮
        /// </summary>
        public void Start()
        {
            if (!_isRunning)
            {
                _isRunning = true;
                _timer.Change(0, _tickDurationMs);
            }
        }

        /// <summary>
        /// 停止时间轮
        /// </summary>
        public void Stop()
        {
            if (_isRunning)
            {
                _isRunning = false;
                _timer.Change(Timeout.Infinite, Timeout.Infinite);
            }
        }

        /// <summary>
        /// 添加任务到时间轮
        /// </summary>
        /// <param name="task">延时任务</param>
        public void AddTask(DelayedTask task)
        {
            if (task == null)
                throw new ArgumentNullException(nameof(task));

            // 计算延迟时间（毫秒）
            var delayMs = (long)(task.ExecuteTimeUtc - DateTime.UtcNow).TotalMilliseconds;

            // 如果已经过期，立即执行
            if (delayMs <= 0)
            {
                Task.Run(() => _taskExecutor(task));
                return;
            }

            // 计算需要多少个时间间隔
            var ticks = (int)Math.Ceiling(delayMs / (double)_tickDurationMs);

            // 计算槽位索引和圈数
            var slotIndex = (_currentSlotIndex + ticks) % _slotCount;
            var rounds = (int)Math.Floor((_currentSlotIndex + ticks) / (double)_slotCount);

            // 添加到槽位
            _slots[slotIndex].Enqueue(task);
            _taskPositions.TryAdd(task.TaskId, (slotIndex, rounds));
        }

        /// <summary>
        /// 从时间轮移除任务
        /// </summary>
        /// <param name="taskId">任务ID</param>
        /// <returns>是否移除成功</returns>
        public bool RemoveTask(string taskId)
        {
            if (_taskPositions.TryRemove(taskId, out var position))
            {
                // 这里简化处理，实际中可能需要创建一个标记为已删除的任务列表
                // 或者在处理时检查任务是否已被移除
                return true;
            }

            return false;
        }

        /// <summary>
        /// 定时器回调，推进时间轮并执行到期任务
        /// </summary>
        private void OnTimerElapsed(object state)
        {
            if (!_isRunning)
                return;

            try
            {
                // 处理当前槽位的任务
                while (_slots[_currentSlotIndex].TryDequeue(out var task))
                {
                    // 检查任务是否存在且圈数为0
                    if (_taskPositions.TryGetValue(task.TaskId, out var position) && position.rounds == 0)
                    {
                        _taskPositions.TryRemove(task.TaskId, out _);

                        // 异步执行任务，避免阻塞时间轮
                        Task.Run(() => _taskExecutor(task));
                    }
                    // 如果圈数大于0，则减少圈数并重新加入槽位
                    else if (position.rounds > 0)
                    {
                        _taskPositions.TryUpdate(task.TaskId, (position.slotIndex, position.rounds - 1), position);
                        _slots[_currentSlotIndex].Enqueue(task);
                    }
                }

                // 移动到下一个槽位
                _currentSlotIndex = (_currentSlotIndex + 1) % _slotCount;
            }
            catch (Exception ex)
            {
                // 记录异常，避免时间轮停止
                Console.WriteLine($"时间轮处理异常: {ex.Message}");
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (_isDisposed) return;

            if (disposing)
            {
                Stop();
                _timer.Dispose();
            }

            _isDisposed = true;
        }

        ~TimingWheel()
        {
            Dispose(false);
        }
    }
}
